"""
Various toolbars used within the main window
"""

import sys
import wx

from menu import Menu
from ArtManager import ArtManager
from LMG.Utility.constants import *

################################################################

class ToolBarDialog(wx.Dialog):
    """
    Allows a user to alter the settings and appearance of 
    columns in a ABCBar.
    """
    def __init__(self, toolbar):
                
        self.toolbar = toolbar
        
        title = _('Customize toolbar')        
        wx.Dialog.__init__(self, self.toolbar, -1, title)

        outerbox = wx.BoxSizer(wx.VERTICAL)

        # Toolbar items
        self.toolbarPanel = ToolBarPanel(self, self.toolbar)

        # Toolbar Options
        toolbarOptionsBox = wx.BoxSizer(wx.HORIZONTAL)
        # text
        self.toolbarStyle = wx.Choice(self, -1, choices = (_('Icons Only'), _('Text Only'), _('Icons & Text')))
        self.toolbarStyle.SetSelection(utility.config.Read('tb_style', "int"))
        # size
        self.toolbarSize = wx.Choice(self, -1, choices = (_('Small'), _('Medium'), _('Large')))
        self.toolbarSize.SetSelection(utility.config.Read('tb_size', "int"))
        toolbarOptionsBox.Add(wx.StaticText(self, wx.ID_STATIC, _('Show: ')), 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        toolbarOptionsBox.Add(self.toolbarStyle, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        toolbarOptionsBox.Add(wx.StaticText(self, wx.ID_STATIC, _('Size: ')), 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        toolbarOptionsBox.Add(self.toolbarSize, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)

        # Buttons
        okbtn  = wx.Button(self, wx.ID_OK, _('OK'))
        okbtn.SetDefault()
        self.Bind(wx.EVT_BUTTON, self._onOK, okbtn)
	cancelbtn = wx.Button(self, wx.ID_CANCEL, _('Cancel'))
        applybtn  = wx.Button(self, wx.ID_APPLY, _('Apply'))
        self.Bind(wx.EVT_BUTTON, self._onApply, applybtn)
        setDefaultsbtn = wx.Button(self, wx.ID_REVERT_TO_SAVED, _('Revert to Saved'))
        self.Bind(wx.EVT_BUTTON, self.toolbarPanel.setDefaults, setDefaultsbtn)
        
        buttonbox = wx.BoxSizer(wx.HORIZONTAL)
        buttonbox.Add(okbtn, 0, wx.EXPAND|wx.ALL, 5)
        buttonbox.Add(applybtn, 0, wx.EXPAND|wx.ALL, 5)
        buttonbox.Add(cancelbtn, 0, wx.EXPAND|wx.ALL, 5)
        buttonbox.Add(setDefaultsbtn, 0, wx.EXPAND|wx.ALL, 5)
        
        outerbox.Add(self.toolbarPanel, 0, wx.EXPAND|wx.ALL, 5)
        outerbox.Add(toolbarOptionsBox, 0, wx.ALIGN_LEFT|wx.ALL, 5)
        outerbox.Add(buttonbox, 0, wx.CENTER)
       
        self.SetAutoLayout(True)
        self.SetSizerAndFit(outerbox)
        
    def _onOK(self, event = None):
        if self.apply():
            event.Skip()
        else:
            self.EndModal(wx.ID_CANCEL)
    
    def _onApply(self, event = None, update = True):
        if self.apply():
            self.toolbar.updateItems(setbitmap = True)
            utility.frame._Refresh()

    def apply(self):
        # Items
        changed = self.toolbarPanel.apply()

        # Size
        if utility.config.Write('tb_size', self.toolbarSize.GetSelection(), "int"):
            changed = True

        # Style
        styleOption = self.toolbarStyle.GetSelection()
        if utility.config.Write('tb_style', styleOption, "int"):
            changed = True
            # Icons Only
            if styleOption == 0:
                style = self.toolbar.GetWindowStyle() & ~wx.TB_TEXT & ~wx.TB_NOICONS
            # Text Only
            elif styleOption == 1:
                style = self.toolbar.GetWindowStyle() | wx.TB_TEXT | wx.TB_NOICONS
            # Both
            else:
                style = (self.toolbar.GetWindowStyle() | wx.TB_TEXT) & ~wx.TB_NOICONS
            self.toolbar.SetWindowStyle(style)
	
        if changed:
            utility.config.Flush()

        return changed


################################################################

class ToolBarPanel(wx.Panel):
    """
    Contains the interface elements for a ToolBarDialog
    """
    def __init__(self, parent, toolbar):
        wx.Panel.__init__(self, parent, -1)
        
        self.parent = parent

        self.toolbar = toolbar
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        listsizer = wx.BoxSizer(wx.HORIZONTAL)
        
        self.lists = {}
        self.lists["available"] = ActionButtonsList(self, _('Available Buttons'), [])
        self.lists["current"] = ActionButtonsList(self, _('Current Buttons'), [])
        
        listsizer.Add(self.lists["available"],
                      0,
                      wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        
        addremovesizer = wx.BoxSizer(wx.VERTICAL)
        
        self.buttons = {}
        
        self.buttons["add"] = utility.makeBitmapButton(self, wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_TOOLBAR), _('Add'), self._addButton)
        addremovesizer.Add(self.buttons["add"], 0, wx.ALIGN_CENTER|wx.ALL, 5)
        
        self.buttons["remove"] = utility.makeBitmapButton(self, wx.ArtProvider.GetBitmap(wx.ART_CROSS_MARK, wx.ART_TOOLBAR), _('Remove'), self._removeButton)
        addremovesizer.Add(self.buttons["remove"], 0, wx.ALIGN_CENTER|wx.ALL, 5)
        
        listsizer.Add(addremovesizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        
        listsizer.Add(self.lists["current"], 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)

        updownsizer = wx.BoxSizer(wx.VERTICAL)
        self.buttons["up"] = utility.makeBitmapButton(self, wx.ArtProvider.GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR), _('Move up'), self._OnMove)
        updownsizer.Add(self.buttons["up"], 0, wx.ALIGN_CENTER|wx.ALL, 5)

        self.buttons["down"] = utility.makeBitmapButton(self, wx.ArtProvider.GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR), _('Move down'), self._OnMove)
        updownsizer.Add(self.buttons["down"], 0, wx.ALIGN_CENTER|wx.ALL, 5)

        listsizer.Add(updownsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        
        sizer.Add(listsizer, 1, wx.EXPAND)
        
        self.loadValues()
        
        self.SetSizerAndFit(sizer)
        
    def getAvailable(self):
        available = []
        
        # Always include the separator
        actionid = ACTION_SEPARATOR
        action = utility.actions[actionid]
        if action.bitmap is not None:
            available.append(actionid)
        
        for actionid in utility.actions:
            action = utility.actions[actionid]
            if action.bitmap is not None and (actionid != ACTION_SEPARATOR):
                if (actionid not in self.lists["current"].items):
                    available.append(actionid)
                
        return available
        
    def getSelected(self, listname = "current"):
        return self.lists[listname].list.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)
        
    def _addButton(self, event = None):
        # Get the button selected on the left
        index = self.getSelected("available")
        if index == -1:
            # Nothing selected on the left
            return
        
        buttonid = self.lists["available"].buttonlist[index]
        
        # Remove it from the left
        if buttonid != ACTION_SEPARATOR:
            self.lists["available"].removeItem(index)
        
        # Add it to the right
        index = self.lists["current"].addItem(buttonid)
        self.lists["current"].selectItem(index)
        
    def _removeButton(self, event = None):
        # Get the button selected on the right
        index = self.getSelected("current")
        if index == -1:
            # Nothing selected on the right
            return
            
        buttonid = self.lists["current"].buttonlist[index]
        
        # Remove it from the right
        self.lists["current"].removeItem(index)
        
        # Add it from the left
        if buttonid != ACTION_SEPARATOR:
            index = self.lists["available"].addItem(buttonid)
            self.lists["available"].selectItem(index)
            
            
    def _OnMove(self, event = None):       
        # Get the button selected on the right
        index = self.getSelected("current")
        if index == -1:
            # Nothing selected on the right
            return
        
        # Move up
        if event.GetId() == self.buttons["up"].GetId():
            direction = -1
        # Move down
        else:
            direction = 1
        
        self.lists["current"].move(index, direction)
                
    def apply(self):       
        changed = utility.config.Write(self.toolbar.configlabel, self.lists["current"].buttonlist, "bencode-list")
        return changed
        
    def loadValues(self, Read = None):
        if Read is None:
            Read = utility.config.Read
        
        self.lists["current"].items = Read(self.toolbar.configlabel, "bencode-list")
        self.lists["available"].items = self.getAvailable()
        
        self.lists["current"].setupItems()
        self.lists["available"].setupItems()
        
    def setDefaults(self, event = None):
        self.loadValues(utility.config.ReadDefault)
               

##############################################################

class ActionButtonsList(wx.Panel):
    """
    List of action buttons
    """
    def __init__(self, parent, label, items):
        wx.Panel.__init__(self, parent, -1)
        
        self.parent = parent
        
        self.label = label
        self.items = items
        self.buttonlist = []
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        sizer.Add(wx.StaticText(self, -1, self.label), 0, wx.ALL, 5)
        
        self.list = wx.ListCtrl(self, -1, size = (210, 300), style = wx.LC_REPORT|wx.LC_NO_HEADER|wx.LC_SINGLE_SEL)
        self._setupList()
        
        sizer.Add(self.list, 1, wx.ALL, 5)
        
        self.SetSizerAndFit(sizer)
        
        self.firsttime = True
        
    def _setupList(self):
        self.list.SetImageList(utility.imagelist["list"], wx.IMAGE_LIST_SMALL)
        
        info = wx.ListItem()
        info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
        info.m_image = -1
        info.m_format = 0
        info.m_text = " "
        self.list.InsertColumnInfo(0, info)
               
    def setupItems(self):
        if not self.firsttime:
            # Only need to delete items after the first time
            self.list.DeleteAllItems()
                
        self.buttonlist = []
        for actionid in self.items:
            self.addItem(actionid, resizecol = False)
            
        self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
        
        self.firsttime = False
        
    def selectItem(self, index):
        self.list.Select(index)
        if self.list.GetItemCount() > 0:
            self.list.EnsureVisible(index)
        
    def addItem(self, actionid, resizecol = True):
        try:
            action = utility.actions[actionid]
            utility.imagelist["idToImage"][actionid]
        except:
            return
        
        index = self.list.GetItemCount()
        text = action.shortdesc
        imageindex = utility.imagelist["idToImage"][actionid]
        self.list.InsertImageStringItem(index, text, imageindex)
        self.buttonlist.append(actionid)
        
        if resizecol:
            self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
        
        return index
        
    def removeItem(self, index):
        self.list.DeleteItem(index)
        del self.buttonlist[index]
        
        self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
        
    def move(self, index, dir):
        if dir == -1 and index == 0:
            # moving up and already at the top
            return
        elif dir == 1 and index == len(self.buttonlist) - 1:
            # moving down and already at the bottom
            return
        
        index2 = index + dir
        
        # Get items
        item = self.list.GetItem(index)        
        item2 = self.list.GetItem(index2)

        # Swap text and images
        item.m_image, item2.m_image = item2.m_image, item.m_image
        item.m_text, item2.m_text = item2.m_text, item.m_text

        # Set items
        self.list.SetItem(item)
        self.list.SetItem(item2)
        
        # Swap indexes
        self.buttonlist[index], self.buttonlist[index2] = self.buttonlist[index2], self.buttonlist[index]
        
        # Update the selection
        self.selectItem(index2)
        

##############################################################

class BaseBar(wx.ToolBar):
    """
    Generic toolbar class
    """
    def __init__(self, parent, configlabel, style = None, hspacing = 0, vspacing = 0):
        self.parent = parent
        
        self.hspacing = hspacing
        self.vspacing = vspacing
        self.firsttime = True
        self.endColour = None

        if style is None:
            style = wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_NODIVIDER | wx.CLIP_CHILDREN
        wx.ToolBar.__init__(self, parent, -1, style = style)

        styleOption = utility.config.Read('tb_style', "int")
        if styleOption == 0:
            style = style & ~wx.TB_TEXT
            self.SetWindowStyle(style)
        elif styleOption == 1:
            style = style | wx.TB_NOICONS
            self.SetWindowStyle(style)
        
            
        self.configlabel = configlabel
        
        self.items = []
        self.toolcount = 0
        
        self.updateItems()

        self.Bind(wx.EVT_TOOL_RCLICKED, self._onRightClick)

    def SetGradientBackground(self, endColour = None, percentage = 70):
        if ArtManager.Get().isDefTheme():
            self.endColour = None
            self.Refresh()
            return

        startup = self.endColour is None

        self.startColour = ArtManager.Get().LightColour(endColour, percentage+20)
        if endColour is None:
            self.endColour = ArtManager.Get().LightColour(self.startColour, percentage)
        else:
            self.endColour = ArtManager.Get().LightColour(endColour, 20)

        if self.endColour == wx.WHITE:
            self.colourDirection = wx.NORTH
        else:
            self.colourDirection = wx.SOUTH

        if startup:
            self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnGradientEraseBackground)
            self.Refresh()
        else:
            self.Refresh()
            
    def OnGradientEraseBackground(self, event):
        """
        Handles the wx.EVT_ERASE_BACKGROUND event.
        """
        if ArtManager.Get().isDefTheme():
            event.Skip()
            self.Unbind(wx.EVT_ERASE_BACKGROUND)
            return
        
        dc = event.GetDC()
        dc.Clear()
        dc.GradientFillLinear(self.GetClientRect(), self.startColour, self.endColour, self.colourDirection)
                    
    def _onRightClick(self, event):
        menu = Menu()
        utility.actions[ACTION_CUSTOMIZE_TOOLBAR].addToMenu(menu)
        utility.makePopup(menu, self.OnHide, _('Hide Toolbar'))
        self.PopupMenu(menu)

    def OnHide(self, event):
        utility.actions[ACTION_VIEWTOOLBAR].action()
        
    def onToolbarDialog(self, event = None):
        dialog = ToolBarDialog(self)
        result = dialog.ShowModal()
        dialog.Destroy()
        if result == wx.ID_OK:
            self.updateItems(setbitmap = True)
            utility.frame._Refresh()

    def updateItems(self, setbitmap = False):
        self.items = utility.config.Read(self.configlabel, "bencode-list")
        
        # Remove from item toolbars if needed:
        for actionid in utility.actions:
            if actionid in utility.actions:
                action = utility.actions[actionid]
                action.removeFromToolbar(self)

        # Remove old items:
        while self.toolcount > 0:
            self.DeleteToolByPos(0)
            self.toolcount -= 1

        # Add new items
        self.firsttime = True

        if setbitmap:
            [action.setBitmap() for action in utility.actionGroup['mainToggle']]                

        for item in self.items:
            if item == -1:
                self.AddSeparator()
                self.toolcount += 1
            elif item in utility.actions:
                if setbitmap:
                    utility.actions[item].setBitmap()
                if utility.actions[item].bitmap is not None:
                    utility.actions[item].addToToolbar(self)
                    self.toolcount += 1
                        
        self.Realize()
        self.Refresh()

        # Fix Check/Radio Items
        utility.actions[ACTION_TORRENTDETAILS].updateButton()
        for action in utility.actionGroup['mainToggle']:
            action.updateButton()